/*
 * 参考链接：
 * 1. https://www.jianshu.com/p/9c2c1416d894
 * 2. https://blog.csdn.net/huweiliyi/article/details/105779329
 * 3. https://blog.csdn.net/chennai1101/article/details/82970070
 */

package com.example.bbs.ui.activity;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;

import com.alibaba.fastjson.JSON;
import com.example.bbs.R;
import com.example.bbs.base.Data;
import com.example.bbs.bean.PostQueryParams;
import com.example.bbs.bean.SearchHistory;
import com.example.bbs.ui.fragment.BaseTabViewPageFragment;
import com.example.bbs.ui.fragment.HomeFragment;
import com.example.bbs.ui.fragment.PostBrowseFragment;
import com.example.bbs.util.BaseUtil;
import com.example.bbs.util.DisplayUtil;
import com.example.bbs.util.FileUtil;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;

@SuppressWarnings("unused")
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    class TabAdapter extends FragmentStateAdapter {

        int itemNum;

        public TabAdapter(@NonNull FragmentActivity fragmentActivity, int itemNum) {
            super(fragmentActivity);
            this.itemNum = itemNum;
        }

        @NonNull
        @Override
        public Fragment createFragment(int position) {
            return mFragmentList.get(position);
        }

        @Override
        public int getItemCount() {
            return itemNum;
        }
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        TextView tvSearchText;
        TextView tvSearchTime;
        ConstraintLayout clInner;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            tvSearchText = itemView.findViewById(R.id.tv_search_text);
            tvSearchTime = itemView.findViewById(R.id.tv_search_time);
            clInner = itemView.findViewById(R.id.cl_inner_item_search_history);
            itemView.setOnClickListener(v -> {
                etSearch.setText(tvSearchText.getText());
                etSearch.setSelection(etSearch.getText().length());
            });
        }

        public void setContent(SearchHistory searchHistory) {
            tvSearchText.setText(searchHistory.getSearchText());
            long time = searchHistory.getTime();
            SimpleDateFormat format_check = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
            SimpleDateFormat format_today = new SimpleDateFormat("HH:mm", Locale.getDefault());
            SimpleDateFormat format_before = new SimpleDateFormat("MM月dd日 HH:mm", Locale.getDefault());
            if (format_check.format(new Date()).equals(format_check.format(new Date(time)))) {
                tvSearchTime.setText(format_today.format(new Date(time)));
            } else {
                tvSearchTime.setText(format_before.format(new Date(time)));
            }
            DisplayUtil.setViewSize(clInner, llSearchPage.getWidth(), clInner.getHeight());
        }
    }

    public class Adapter extends RecyclerView.Adapter<ViewHolder> {

        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = View.inflate(MainActivity.this, R.layout.view_item_main_search_history, null);
            return new ViewHolder(view);
        }

        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, @SuppressLint("RecyclerView") int position) {
            holder.setContent(mSearchHistoryList.get(position));
        }

        @Override
        public int getItemCount() {
            return mSearchHistoryList.size();
        }
    }

    public static final String INTENT_EXTRA_POST = "post"; // type: Post
    public static final int TAB_POS_POST_LIST = 0;
    public static final int TAB_POS_HOME = 2;
    static final String LOG_TAG = MainActivity.class.getSimpleName();
    static final String SEARCH_HISTORY_PREFERENCE_NAME = "searchHistoryListJson";
    static final DisplayImageOptions ICON_DISPLAY_OPTIONS = new DisplayImageOptions.Builder()
            .cacheInMemory(true)
            .cacheOnDisk(true)
            .displayer(new RoundedBitmapDisplayer(20))
            .build();

    TabLayout tlMain;
    ViewPager2 vpMain;
    ConstraintLayout clSearchPage;
    LinearLayout llSearchPage;
    TextView tvSearchTypeAll;
    TextView tvSearchTypeTitle;
    TextView tvSearchTypeContent;
    TextView tvSearchTypeAuthor;
    ActionBar actionBar;
    ImageView ivIcon;
    EditText etSearch;
    ImageView ivSearch;
    RecyclerView rvSearchHistory;
    int mSearchType;
    String mIconUrl = "";
    Bitmap mIconBitmap = null;
    Adapter mSearchHistoryAdapter;
    List<BaseTabViewPageFragment> mFragmentList;
    List<SearchHistory> mSearchHistoryList;
    SharedPreferences mSharedPreferences;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(LOG_TAG, "onCreate");
        setContentView(R.layout.activity_main);

        // 搜索历史应该保存在本地。
        mSharedPreferences = this.getSharedPreferences(FileUtil.BASE_PREFERENCES_FILE, Context.MODE_PRIVATE);
        mSearchHistoryList = new ArrayList<>();
        if (mSharedPreferences != null) {
            String jsonStrSearchHistory = mSharedPreferences.getString(SEARCH_HISTORY_PREFERENCE_NAME, "");
            Log.d(LOG_TAG, "load: " + jsonStrSearchHistory);
            if (!jsonStrSearchHistory.isEmpty()) {
                mSearchHistoryList = JSON.parseArray(jsonStrSearchHistory, SearchHistory.class);
            }
        }

        initView();
        initClickListener();
    }

    void initView() {
        clSearchPage = findViewById(R.id.cl_search_page);
        llSearchPage = findViewById(R.id.ll_search_page);
        tvSearchTypeAll = findViewById(R.id.tv_search_type_all);
        tvSearchTypeTitle = findViewById(R.id.tv_search_type_title);
        tvSearchTypeContent = findViewById(R.id.tv_search_type_content);
        tvSearchTypeAuthor = findViewById(R.id.tv_search_type_author);
        rvSearchHistory = findViewById(R.id.rv_search_history);

        clSearchPage.setVisibility(View.INVISIBLE);
        // 默认选项
        setBinaryButton(tvSearchTypeTitle, true);
        mSearchType = PostQueryParams.SEARCH_TYPE_TITLE;
        mSearchHistoryAdapter = new Adapter();
        rvSearchHistory.setAdapter(mSearchHistoryAdapter);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        rvSearchHistory.setLayoutManager(layoutManager);

        initViewPager();
        initTab();
        initActionBar();
    }

    private void initClickListener() {
        tvSearchTypeAll.setOnClickListener(this);
        tvSearchTypeTitle.setOnClickListener(this);
        tvSearchTypeContent.setOnClickListener(this);
        tvSearchTypeAuthor.setOnClickListener(this);
        ivSearch.setOnClickListener(this);
        ivIcon.setOnClickListener(this);
    }

    void initViewPager() {
        mFragmentList = new ArrayList<>();
        mFragmentList.add(PostBrowseFragment.newInstance(false));
        mFragmentList.add(PostBrowseFragment.newInstance(true));
        mFragmentList.add(HomeFragment.newInstance());

        vpMain = findViewById(R.id.vp_main);
        TabAdapter adapter = new TabAdapter(this, mFragmentList.size());
        vpMain.setAdapter(adapter);
    }

    // TODO(Low): 改一下 Tab 的样式，先用默认值。
    void initTab() {
        tlMain = findViewById(R.id.tl_main);
        for (int i = 0; i < mFragmentList.size(); i++) {
            TabLayout.Tab newTab = tlMain.newTab();
            newTab.setText(mFragmentList.get(i).getName());
            tlMain.addTab(newTab);
        }
        tlMain.setTabGravity(TabLayout.GRAVITY_FILL);
        tlMain.addOnTabSelectedListener(
            new TabLayout.OnTabSelectedListener() {
                @Override
                public void onTabSelected(TabLayout.Tab tab) {
                    int index = tab.getPosition();
                    if (index >= 0 && index < mFragmentList.size()) {
                        vpMain.setCurrentItem(index);
                    }
                    if (actionBar != null) {
                        vpMain.postDelayed(() -> {
                            if (index == TAB_POS_HOME) {
                                actionBar.hide();
                            } else {
                                actionBar.show();
                            }
                        }, DisplayUtil.VIEW_PAGER_SHIFTING_TIME);
                    }
                    if (etSearch != null)
                        etSearch.setText("");
                }
                @Override
                public void onTabUnselected(TabLayout.Tab tab) { }
                @Override
                public void onTabReselected(TabLayout.Tab tab) { }
            });
        // TabLayout 在绑定 ViewPager 时，会出现 title 被移除的情况，因此需要重写 TabConfigurationStrategy
        new TabLayoutMediator(tlMain, vpMain,
                (tab, position) -> tab.setText(mFragmentList.get(position).getName())
        ).attach();
    }

    public void initActionBar() {
        actionBar = getSupportActionBar();
        if (actionBar == null)
            return;
        actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
        actionBar.setCustomView(R.layout.menu_post_browse);

        View actionView = actionBar.getCustomView();
        ivSearch = actionView.findViewById(R.id.iv_search);
        etSearch = actionView.findViewById(R.id.et_search);
        ivIcon = actionView.findViewById(R.id.iv_icon);

        etSearch.setOnFocusChangeListener((v, hasFocus) -> {
            if (hasFocus) {
                switchLayoutToSearch();
            } else {
                Log.w(LOG_TAG, "quit search unexpectedly");
                switchLayoutToMain();
            }
        });
        etSearch.setOnEditorActionListener((v, actionId, event) -> {
            if (actionId == EditorInfo.IME_ACTION_SEND ||
                    (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
                search();
                return true;
            }
            return false;
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(LOG_TAG, "onStart");
    }

    @Override
    public void onResume() {
        super.onResume();
        refreshIcon();
        Log.d(LOG_TAG, "onResume");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(LOG_TAG, "onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(LOG_TAG, "onStop");

        SharedPreferences.Editor editor = mSharedPreferences.edit();
        editor.putString(SEARCH_HISTORY_PREFERENCE_NAME, JSON.toJSONString(mSearchHistoryList));
        Log.d(LOG_TAG, "save: " + JSON.toJSONString(mSearchHistoryList));
        editor.apply();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(LOG_TAG, "onDestroy");
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();

        if (id == R.id.iv_search) {
            search();

        } else if (id == R.id.tv_search_type_all) {
            boolean state = !tvSearchTypeAll.isSelected();
            for (TextView textView : new TextView[] { tvSearchTypeAll, tvSearchTypeTitle, tvSearchTypeContent, tvSearchTypeAuthor }) {
                setBinaryButton(textView, state);
            }
            setSearchType(PostQueryParams.SEARCH_TYPE_ALL, v.isSelected());

        } else if (id == R.id.tv_search_type_title) {
            setBinaryButton((TextView) v, !v.isSelected());
            setSearchType(PostQueryParams.SEARCH_TYPE_TITLE, v.isSelected());

        } else if (id == R.id.tv_search_type_content) {
            setBinaryButton((TextView) v, !v.isSelected());
            setSearchType(PostQueryParams.SEARCH_TYPE_CONTENT, v.isSelected());

        } else if (id == R.id.tv_search_type_author) {
            setBinaryButton((TextView) v, !v.isSelected());
            setSearchType(PostQueryParams.SEARCH_TYPE_AUTHOR, v.isSelected());

        } else if (id == R.id.iv_icon) {
            if (clSearchPage.getVisibility() == View.VISIBLE) {
                etSearch.setText("");
                PostBrowseFragment currentFragment = (PostBrowseFragment) mFragmentList.get(vpMain.getCurrentItem());
                if (currentFragment == null) {
                    Log.d(LOG_TAG, "wrong fragment when search");
                    return;
                }
                currentFragment.getQueryParams().setKeywords(new String[]{});
                currentFragment.getQueryParams().setSearchType(PostQueryParams.SEARCH_TYPE_NO_SEARCH);
                switchLayoutToMain();
                currentFragment.reset();
            } else {
                Intent intent = new Intent();
                intent.setClass(MainActivity.this, MyOwnInfoActivity.class);
                startActivity(intent, new Bundle());
            }
        }
    }

    public void setBinaryButton(TextView textView, boolean selected) {
        if (selected) {
            textView.setBackgroundResource(R.drawable.border_color_theme_round_3);
            textView.setTextColor(getColor(R.color.primary));
        } else {
            textView.setBackgroundResource(R.drawable.border_round_3);
            textView.setTextColor(getColor(R.color.light_grey));
        }
        textView.setSelected(selected);
    }

    public void setSearchType(int mask, boolean value) {
        if (value)
            mSearchType = mSearchType | mask;
        else
            mSearchType = mSearchType & ~mask;
    }

    public void refreshIcon() {
        if (Data.myself == null || !mIconUrl.isEmpty() && mIconUrl.equals(Data.myself.getAvatarUrl()))
            return;
        CompletableFuture.runAsync(() -> {
            Bitmap iconBitmap = ImageLoader.getInstance().loadImageSync(Data.myself.getAvatarUrl(),
                    ICON_DISPLAY_OPTIONS);
            if (actionBar != null) {
                actionBar.setIcon(new BitmapDrawable(getResources(), iconBitmap));
            }
        });
    }

    // TODO(Low): 偶尔会出现页面变灰，有时间再细查。
    public void search() {
        if (mSearchType == 0) {
            BaseUtil.showToast(R.string.toast_empty_search_type);
            return;
        }
        String text = etSearch.getText().toString();
        if (!text.isEmpty()) {
            for (SearchHistory searchHistory : mSearchHistoryList) {
                if (text.equals(searchHistory.getSearchText())) {
                    mSearchHistoryList.remove(searchHistory);
                    break;
                }
            }
            mSearchHistoryList.add(0, new SearchHistory(text, System.currentTimeMillis()));
        }
        String[] keywords = text.split("\\s+");
        PostBrowseFragment currentFragment = (PostBrowseFragment) mFragmentList.get(vpMain.getCurrentItem());
        if (currentFragment == null) {
            Log.d(LOG_TAG, "wrong fragment when search");
            return;
        }
        currentFragment.getQueryParams().setKeywords(keywords);
        currentFragment.getQueryParams().setSearchType(mSearchType);
        switchLayoutToMain();
        currentFragment.reset();
    }

    @SuppressLint("NotifyDataSetChanged")
    public void switchLayoutToSearch() {
        clSearchPage.setVisibility(View.VISIBLE);
        ivIcon.setImageResource(R.drawable.main_back);
        ivSearch.setImageResource(R.drawable.main_search_heavy);
        mSearchHistoryAdapter.notifyDataSetChanged();
    }

    public void switchLayoutToMain() {
        clSearchPage.setVisibility(View.GONE);
        DisplayUtil.cancelFocus(this, etSearch);
        if (mIconBitmap == null) {
            ivIcon.setImageResource(R.drawable.login_head);
        } else {
            ivIcon.setImageBitmap(mIconBitmap);
        }
        ivSearch.setImageResource(R.drawable.main_search_light);
    }
}